﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.Core;
using Castle.Core.Internal;
using Castle.MicroKernel;
using Castle.Windsor;
using Xray.Common;

namespace Xray.Windsor
{
    public class XrayWindsor : XrayClient
    {
        private readonly IWindsorContainer _container;
        private IHandler[] _handlers;

        public XrayWindsor(IWindsorContainer container)
        {
            _container = container;
        }

        protected override Model PopulateModel()
        {
            Model model = new Model();

            IKernel kernel = _container.Kernel;

            _handlers = kernel.GetAssignableHandlers(typeof (object));
            //get the components
            foreach (IHandler handler in _handlers)
            {
                Component component = new Component();
                component.Name = GetName(handler);
                component.Namespace = GetNamespace(handler);
                
                model.Components.Add(component);
            }


            //update with dependents
            foreach (IHandler handler in _handlers)
            {
                string fullName = GetFullName(handler);
                Component component = model.FindComponentByFullName(fullName);

                //constructor dependencies
                foreach (DependencyModel ctorDependency in handler.ComponentModel.Constructors.FewerArgumentsCandidate.Dependencies)
                {
                    Type dependentType = ctorDependency.TargetItemType;

                    AddComponentDependency(model, component, dependentType);
                }

                //property dependencies
                foreach (PropertySet property in handler.ComponentModel.Properties)
                {
                    Type dependentType = property.Dependency.TargetItemType;

                    AddComponentDependency(model, component, dependentType);
                    
                }
            }

            return model;
        }

        private void AddComponentDependency(Model model, Component component, Type dependentType)
        {
            Type actualDependentType = dependentType.IsGenericType
                ? dependentType.GetGenericTypeDefinition()
                : dependentType;

            IHandler dependentHandler = _handlers.Where(x => x.ComponentModel.Service == actualDependentType).FirstOrDefault();
            if (dependentHandler == null)
            {
                return;
            }

            string dependentFullName = GetFullName(dependentHandler);
            Component dependentComponent = model.FindComponentByFullName(dependentFullName);

            component.AddDependent(dependentComponent);
        }

        private string GetFullName(IHandler handler)
        {
            return handler.ComponentModel.Implementation.FullName;   
        }

        private string GetNamespace(IHandler handler)
        {
            return handler.ComponentModel.Implementation.Namespace;
        }

        private string GetName(IHandler handler)
        {
            return handler.ComponentModel.Implementation.Name.Replace(".","");
        }
    }


}
